package cn.matrix42.potoo.jdbc.dialect;

import java.util.Arrays;
import java.util.stream.Collectors;

import static java.lang.String.format;

public abstract class AbstractDialect implements Dialect {

    @Override
    public String getInsertIntoStatement(String tableName, String[] fieldNames) {
        String columns =
            Arrays.stream(fieldNames)
                .map(this::quoteIdentifier)
                .collect(Collectors.joining(", "));
        String placeholders =
            Arrays.stream(fieldNames).map(f -> ":" + f).collect(Collectors.joining(", "));
        return "INSERT INTO "
            + quoteIdentifier(tableName)
            + "("
            + columns
            + ")"
            + " VALUES ("
            + placeholders
            + ")";
    }

    /**
     * A simple single row {@code UPDATE} statement.
     *
     * <pre>{@code
     * UPDATE table_name
     * SET col = val [, ...]
     * WHERE cond [AND ...]
     * }</pre>
     */
    @Override
    public String getUpdateStatement(
        String tableName, String[] fieldNames, String[] conditionFields) {
        String setClause =
            Arrays.stream(fieldNames)
                .map(f -> format("%s = :%s", quoteIdentifier(f), f))
                .collect(Collectors.joining(", "));
        String conditionClause =
            Arrays.stream(conditionFields)
                .map(f -> format("%s = :%s", quoteIdentifier(f), f))
                .collect(Collectors.joining(" AND "));
        return "UPDATE "
            + quoteIdentifier(tableName)
            + " SET "
            + setClause
            + " WHERE "
            + conditionClause;
    }

    /**
     * A simple single row {@code DELETE} statement.
     *
     * <pre>{@code
     * DELETE FROM table_name
     * WHERE cond [AND ...]
     * }</pre>
     */
    @Override
    public String getDeleteStatement(String tableName, String[] conditionFields) {
        String conditionClause =
            Arrays.stream(conditionFields)
                .map(f -> format("%s = :%s", quoteIdentifier(f), f))
                .collect(Collectors.joining(" AND "));
        return "DELETE FROM " + quoteIdentifier(tableName) + " WHERE " + conditionClause;
    }

    /**
     * A simple {@code SELECT} statement.
     *
     * <pre>{@code
     * SELECT expression [, ...]
     * FROM table_name
     * WHERE cond [AND ...]
     * }</pre>
     */
    @Override
    public String getSelectFromStatement(
        String tableName, String[] selectFields, String[] conditionFields) {
        String selectExpressions =
            Arrays.stream(selectFields)
                .map(this::quoteIdentifier)
                .collect(Collectors.joining(", "));
        String fieldExpressions =
            Arrays.stream(conditionFields)
                .map(f -> format("%s = :%s", quoteIdentifier(f), f))
                .collect(Collectors.joining(" AND "));
        return "SELECT "
            + selectExpressions
            + " FROM "
            + quoteIdentifier(tableName)
            + (conditionFields.length > 0 ? " WHERE " + fieldExpressions : "");
    }

    /**
     * A simple {@code SELECT} statement that checks for the existence of a single row.
     *
     * <pre>{@code
     * SELECT 1
     * FROM table_name
     * WHERE cond [AND ...]
     * }</pre>
     */
    @Override
    public String getRowExistsStatement(String tableName, String[] conditionFields) {
        String fieldExpressions =
            Arrays.stream(conditionFields)
                .map(f -> format("%s = :%s", quoteIdentifier(f), f))
                .collect(Collectors.joining(" AND "));
        return "SELECT 1 FROM " + quoteIdentifier(tableName) + " WHERE " + fieldExpressions;
    }

}
